﻿#define _CRT_SECURE_NO_WARNINGS
#include"snke.h"
//实现贪吃蛇函数文件

//定位光标
void SetPos(short x, short y)
{
	COORD pos = { x,y };
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(houtput, pos);
}

//打印欢迎界面
void WelcomeToGame()
{
	SetPos(38, 12);
	wprintf(L"%ls",L"欢迎来到贪吃蛇小游戏");
	SetPos(40, 23);
	system("pause");
	system("cls");

	SetPos(30, 12);
	wprintf(L"%ls", L"用↑.↓.→.←来控制蛇的移动，按F1加速，F2减速");
	SetPos(30, 13);
	wprintf(L"%ls", L"加速可以获得更高的分数。");
	SetPos(40, 23);
	system("pause");
	system("cls");

}

//打印地图
void CreateMap()
{
	//上边墙体
	SetPos(0,0);
	int i = 0;
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//下边墙体
	SetPos(0, 26);
	for (int i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//左边墙体
	for (int i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右边墙体
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

//初始化蛇的身体
void InitSnake(pSnke ps)
{
	//打印蛇的身体
	//创建蛇身的节点并连接
	for (int i = 0; i < 5; i++)
	{
		pSnkeNode newnode = (pSnkeNode)malloc(sizeof(SnkeNode));
		if (newnode == NULL)
		{
			perror("malloc: ");
			return;
		}
		newnode->x = X + i * 2;
		newnode->y = Y;
		newnode->next = NULL;
		//判断蛇头是否为空
		if (ps->_psnke == NULL)
		{
			ps->_psnke = newnode;
		}
		else
		{
			//newnode _psnke
			newnode->next = ps->_psnke;
			ps->_psnke = newnode;
		}
	}
	//打印蛇的身体
	pSnkeNode cur = ps->_psnke;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", SNKE);
		cur = cur->next;
	}
	ps->_FoodScore = 10;
	ps->_Score = 0;
	ps->_SleepTime = 200;
	ps->_dir = RIGHT;
	ps->_state = OK;
}

//设置食物的位置
void CreateFood(pSnke ps)
{
	int x = 0;
	int y = 0;
agin:
	//随机产生的坐标要是2的倍数这样蛇头才可以碰到食物
	do {
		x = rand() % 54 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	//不能让食物和蛇身重合
	pSnkeNode cur = ps->_psnke;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto agin;
		}
		cur = cur->next;
	}
	pSnkeNode Food = (pSnkeNode)malloc(sizeof(SnkeNode));
	if (Food == NULL)
	{
		perror("Food malloc:");
		return;
	}
	else
	{
		Food->x = x;
		Food->y = y;
		Food->next = NULL;
		SetPos(Food->x, Food->y);
		wprintf(L"%lc", FOOD);
		ps->_pfood = Food;
	}
}
//游戏开始
void GameStart(pSnke ps)
{
	//设计窗口大小
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	//隐藏的光标
	//获取句柄
	HANDLE houtput = NULL;
	CONSOLE_CURSOR_INFO info = { 0 };
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleCursorInfo(houtput, &info);
	info.bVisible = false;
	SetConsoleCursorInfo(houtput, &info);
	//打印欢迎界面
	WelcomeToGame();
	//打印地图
	CreateMap();
	//初始化蛇的身体
	InitSnake(ps);
	//设置食物
	CreateFood(ps);
}
//打印右边提示信息
void PrintHelpInfo()
{
	SetPos(65, 13);
	wprintf(L"%ls", L"不能穿墙，不能咬到自己");
	SetPos(65, 14);
	wprintf(L"%ls", L"用↑.↓.→.←来控制蛇的移动.");
	SetPos(65, 15);
	wprintf(L"%ls", L"按F1加速，F2减速.");
	SetPos(65, 16);
	wprintf(L"%ls", L"Esc退出游戏，space暂停游戏");
	SetPos(65, 18);
	wprintf(L"%ls", L"吃蛇小游戏");
}
#define KEY_PRESS(VK)((GetAsyncKeyState(VK)&0x1) ? 1 : 0)
//暂停
void pause()
{
	while (1)
	{   Sleep(200);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
		
	}
}
//维护蛇的指针
int NextIsFood(pSnkeNode pn, pSnke ps)
{
	return (pn->x == ps->_pfood->x) && (pn->y == ps->_pfood->y);
}
//下一个位置不是食物就移动一步
void NoEatFood(pSnkeNode pn, pSnke ps)
{
	//连接下一个位置的节点
	pn->next = ps->_psnke;
	ps->_psnke = pn;
	//打印蛇的身体
	pSnkeNode cur = ps->_psnke;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", SNKE);
		cur = cur->next;
	}
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

//如果下一个位置是食物
void EatFood(pSnkeNode pn, pSnke ps)
{
	//连接蛇头与食物
	ps->_pfood->next = ps->_psnke;
	ps->_psnke = ps->_pfood;
	free(pn);
	pn = NULL;
	//打印蛇的身体
	pSnkeNode cur = ps->_psnke;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", SNKE);
		cur = cur->next;
	}
	ps->_Score += ps->_FoodScore;
	//吃掉了食物那么就再生成一个食物
	CreateFood(ps);
}

//判断是否会撞墙
void KillByWall(pSnke ps)
{
	if ((ps->_psnke->x) > 54 || (ps->_psnke->y) > 24 || (ps->_psnke->x) < 2 || (ps->_psnke->y) < 1)
	{
		ps->_state = KILL_BUY_WALL;
	}
}

//判断是否撞到自己
void KillBySelf(pSnke ps)
{
	//遍历贪吃蛇
	pSnkeNode cur = ps->_psnke->next;
	while (cur)
	{
		if ((ps->_psnke->x) == cur->x && (ps->_psnke->y) == cur->y)
		{
			ps->_state = KILL_BUY_ME;
		}
		cur = cur->next;
	}
}

//蛇移动的实现
void SnakeMove(pSnke ps)
{
	//创建新的节点
	pSnkeNode pNext = (pSnkeNode)malloc(sizeof(SnkeNode));
	if (pNext == NULL)
	{
		perror("pNext");
		return;
	}
	switch (ps->_dir)
	{
	case UP:
		pNext->x = ps->_psnke->x;
		pNext->y = (ps->_psnke->y) - 1;
		break;
	case DOWN:
		pNext->x = ps->_psnke->x;
		pNext->y = (ps->_psnke->y) + 1;
		break;
	case LEFT:
		pNext->x = (ps->_psnke->x) - 2;
		pNext->y = ps->_psnke->y;
		break;
	case RIGHT:
		pNext->x = (ps->_psnke->x) + 2;
		pNext->y = ps->_psnke->y;
		break;
	}
	//判断下一个点是否为食物
	if (NextIsFood(pNext,ps))
	{
		//下一个位置是食物就吃掉食物
		EatFood(pNext,ps);
	}
	else
	{
		//下一个位置不是食物
		NoEatFood(pNext,ps);
	}
	//判断是否撞墙
	KillByWall(ps);
	//判断是否撞到自己
	KillBySelf(ps);
}
//游戏的进行
void GameRun(pSnke ps)
{
	//打印帮助信息
	PrintHelpInfo();
	//首先打印右边的当前分数和食物的分数
	
	//首先检查按键状态因为按键不可能只按一次所以这里使用循环
	do {
		SetPos(65, 10);
		wprintf(L"%ls", L"得分：");
		wprintf(L"%d", ps->_Score);
		wprintf(L"%ls", L"  当前食物分数：");
		wprintf(L"%d", ps->_FoodScore);
		//上键 
		if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
		{
			ps->_dir = UP;
		}
		//下键
		else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
		{
			ps->_dir = DOWN;
		}
		//左键
		else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
		{
			ps->_dir = LEFT;
		}
		//右键
		else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
		{
			ps->_dir = RIGHT;
		}
		//暂停
		else if (KEY_PRESS(VK_SPACE))
		{
			pause();
		}
		//esc
		else if (KEY_PRESS(VK_ESCAPE))
		{
			//正常结束
			ps->_state = ESC;
		}
		//加速
		else if (KEY_PRESS(VK_F1))
		{
			if (ps->_SleepTime > 80)
			{
				ps->_SleepTime -= 30;
				ps->_FoodScore += 2;
			}
		}
		//减速
		else if (KEY_PRESS(VK_F2))
		{
			if (ps->_FoodScore > 2)
			{
				ps->_SleepTime += 30;
				ps->_FoodScore -= 2;
			}
		}
		//蛇的移动
		SnakeMove(ps);
		//每次移动需要停多少长时间，也就是蛇的速度
		Sleep(ps->_SleepTime);
	} while (ps->_state == OK);
}

//游戏结束
void GameEnd(pSnke ps)
{
	SetPos(20,14);
	pSnkeNode cur = ps->_psnke->next;
	switch (ps->_state)
	{
	case ESC:
		printf("您已退出游戏!");
		break;
	case KILL_BUY_ME:
		printf("你撞到自己了！");
		break;
	case KILL_BUY_WALL:
		printf("你撞到墙了！");
		break;
	}
	while (cur)
	{
		free(ps->_psnke);
		ps->_psnke = cur;
		cur = cur->next;
	}
	ps->_psnke = NULL;
}